package com.fsh.subject.domain.reids;

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * RedisUtil工具类
 *
 * @author: ChickenWing
 * @date: 2023/10/28
 */
@Component
@Slf4j
public class RedisUtil {

    @Resource
    private RedisTemplate redisTemplate;

    private static final String CACHE_KEY_SEPARATOR = ".";

    /**
     * 构建缓存key
     */
    public String buildKey(String... strObjs) {
        return Stream.of(strObjs).collect(Collectors.joining(CACHE_KEY_SEPARATOR));
    }

    /**
     * 是否存在key
     */
    public boolean exist(String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 删除key
     */
    public boolean del(String key) {
        return redisTemplate.delete(key);
    }

    /**
     * set(不带过期)
     */
    public void set(String key, String value) {
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * set(带过期)
     */
    public boolean setNx(String key, String value, Long time, TimeUnit timeUnit) {
        return redisTemplate.opsForValue().setIfAbsent(key, value, time, timeUnit);
    }

    /**
     * 获取string类型缓存
     */
    public String get(String key) {
        return (String) redisTemplate.opsForValue().get(key);
    }

    public Boolean zAdd(String key, String value, Long score) {
        return redisTemplate.opsForZSet().add(key, value, Double.valueOf(String.valueOf(score)));
    }

    public Long countZset(String key) {
        return redisTemplate.opsForZSet().size(key);
    }

    public Set<String> rangeZset(String key, long start, long end) {
        return redisTemplate.opsForZSet().range(key, start, end);
    }

    public Long removeZset(String key, Object value) {
        return redisTemplate.opsForZSet().remove(key, value);
    }

    public void removeZsetList(String key, Set<String> value) {
        value.stream().forEach((val) -> redisTemplate.opsForZSet().remove(key, val));
    }

    public Double score(String key, Object value) {
        return redisTemplate.opsForZSet().score(key, value);
    }

    public Set<String> rangeByScore(String key, long start, long end) {
        return redisTemplate.opsForZSet().rangeByScore(key, Double.valueOf(String.valueOf(start)), Double.valueOf(String.valueOf(end)));
    }

    /**
     * ZINCRBY key increment member：指定key中的member的分数增加 increment值。
     *      若key中没有该member，则创建member并把分数置为increment值
     */
    public Object addScore(String key, Object obj, double score) {
        return redisTemplate.opsForZSet().incrementScore(key, obj, score);
    }

    public Object rank(String key, Object obj) {
        return redisTemplate.opsForZSet().rank(key, obj);
    }
 
    /**
     * ZRANGEBYSCORE key min max：按照score排序后，获取指定score范围内的元素
     */
    public Set<ZSetOperations.TypedTuple<String>> rankWithScore(String key, long start, long end) {
        Set<ZSetOperations.TypedTuple<String>> set = redisTemplate.opsForZSet().reverseRangeWithScores(key, start, end);
        return set;
    }

    public void putHash(String subjectLikedKey, String hashKey, Integer status) {
        redisTemplate.opsForHash().put(subjectLikedKey,hashKey,status);
    }

    public void increment(String countKey, int i) {
        redisTemplate.opsForValue().increment(countKey,i);
    }

    public Integer getInt(String countKey) {
         return (Integer)redisTemplate.opsForValue().get(countKey);
    }

    // 从reids中取出 hash存的数据，并删除
    public Map<Object, Object> getHashAndDelete(String key) {
        // 创建一个新的HashMap对象，用于存储从Redis中获取的数据。
        Map<Object, Object> map = new HashMap<>();
        // 使用redisTemplate的opsForHash().scan方法扫描指定key的Redis哈希结构。
        // 该方法返回一个Cursor对象，其中包含哈希结构中的所有键值对。
        Cursor<Map.Entry<Object, Object>> cursor = redisTemplate.opsForHash().scan(key, ScanOptions.NONE);
        // 使用while循环遍历Cursor中的所有键值对。
        while (cursor.hasNext()) {
            // 获取下一个键值对。
            Map.Entry<Object, Object> entry = cursor.next();
            // 获取键值对的键。
            Object hashKey = entry.getKey();
            // 获取键值对的值。
            Object value = entry.getValue();
            // 将键值对添加到map中。
            map.put(hashKey, value);
            // 使用redisTemplate的opsForHash().delete方法从Redis中删除该键值对。
            redisTemplate.opsForHash().delete(key, hashKey);
        }
        // 返回存储了从Redis中获取的数据的map。
        return map;
    }
}
